package com.server.commons.security.handler;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.server.common.code.error.BusinessException;
import com.server.common.code.error.InsideException;
import com.server.common.code.error.PreAuthorizeException;
import com.server.common.code.utils.AjaxResult;
import com.server.common.security.code.anntation.FieldTypeDontMatch;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.lang.reflect.Field;
import java.net.SocketTimeoutException;
import java.util.Arrays;

@RestControllerAdvice
@Slf4j
public class MyFullErrorHandler {

    /**
     * 全局异常
     * @author LXC
     * @date 2022/4/30 19:20
     */
    @ExceptionHandler(Exception.class)
    public AjaxResult FullError(Exception e){
        log.error("系统繁忙,请稍后再试!",e);
        return AjaxResult.error("系统繁忙,请稍后再试!");
    }

    /**
     * 请求超时,请重试!
     * @author LXC
     * @date 2022/4/30 19:21
     */
    @ExceptionHandler(SocketTimeoutException.class)
    public AjaxResult socketTimeoutError(SocketTimeoutException e){
        log.error("请求超时,请重试!",e);
        return AjaxResult.error("请求超时,请重试!");
    }

    /**
     * 没权限
     * @author LXC
     * @date 2022/4/30 19:21
     */
    @ExceptionHandler(PreAuthorizeException.class)
    public AjaxResult preAuthorizeError(PreAuthorizeException e){
        log.error("没有权限，无法访问!",e);
        return AjaxResult.error("没有权限，无法访问!");
    }


    /**
     * 内部接口
     * @author LXC
     * @date 2022/4/30 19:21
     */
    @ExceptionHandler(InsideException.class)
    public AjaxResult insideError(InsideException e){
        log.error("内部接口,无法访问!",e);
        return AjaxResult.error(404,"404 NOT FIND");
    }

    /**
     * 自己的业务异常
     * @author LXC
     * @date 2022/4/30 19:21
     */
    @ExceptionHandler(BusinessException.class)
    public AjaxResult businessError(BusinessException e){
        log.error(e.getMessage(),e);
        return AjaxResult.error(e.getMessage());
    }

    /**
     * 自定义验证异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Object validExceptionHandler(MethodArgumentNotValidException e)
    {
        log.error(e.getMessage(), e);
        ObjectError objectError = e.getBindingResult()
                .getAllErrors()
                .stream()
                .findFirst()
                .orElseGet(() -> new ObjectError("", "验证异常"));
        return AjaxResult.error(objectError.getDefaultMessage());
    }

    /**
     * 请求内容类型错误
     * @author LXC
     * @date 2022/4/30 19:20
     */
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public AjaxResult httpMediaTypeNotSupportedError(HttpMediaTypeNotSupportedException e){
        log.error(e.getMessage(), e);
        return AjaxResult.error("请求内容类型错误");
    }

    /**
     * 请求方式错误
     * @author LXC
     * @date 2022/4/30 19:20
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public AjaxResult httpRequestMethodNotSupportedError(HttpRequestMethodNotSupportedException e){
        e.printStackTrace();
        log.error(e.getMessage());
        return AjaxResult.error("请求方式错误");
    }

    /**
     * Get请求参数错误时的处理
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    public AjaxResult handleNoHandlerFoundException(NoHandlerFoundException e){
        log.error("路径不存在：{}", e.toString());
        return AjaxResult.error(404, "服务器资源异常");
    }

    /**
     * 参数类型不正确
     * @author LXC
     * @date 2022/12/16 20:51
     */
    public AjaxResult invalidFormatException(InvalidFormatException e){
        for (JsonMappingException.Reference path :e.getPath()){
            Object from = path.getFrom();
            Field[] declaredFields = from.getClass().getDeclaredFields();
            Field fieldNew = Arrays.stream(declaredFields)
                    .filter(field -> field.getName().equals(path.getFieldName()))
                    .findFirst()
                    .orElse(null);
            if(ObjectUtils.isEmpty(fieldNew)){
                break;
            }

            fieldNew.setAccessible(true);
            FieldTypeDontMatch annotation = fieldNew.getAnnotation(FieldTypeDontMatch.class);

            if(ObjectUtils.isEmpty(annotation)){
                break;
            }

            String value = annotation.value();
            return AjaxResult.error(value);
        }
        return AjaxResult.error("请检查参数类型!");
    }

    /**
     * JSON数据不正确
     * @author LXC
     * @date 2022/12/16 20:51
     */
    public AjaxResult jsonParseException(JsonParseException e){
        return AjaxResult.error("数据不正确!");
    }

    /**
     * 参数类型不正确
     * @author LXC
     * @date 2022/12/16 20:51
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public AjaxResult httpMessageNotReadableException(HttpMessageNotReadableException e){
        log.error("请检查参数类型", e);

        if(e.getCause() instanceof InvalidFormatException){
            return invalidFormatException((InvalidFormatException) e.getCause());
        }

        if(e.getCause() instanceof JsonParseException){
            return jsonParseException((JsonParseException) e.getCause());
        }

        return AjaxResult.error("请检查参数类型!");
    }
}
